#ifndef _ENGINE_HPP
#define _ENGINE_HPP

#include "TimeKeeper.hpp"

#include "IInput.hpp"

//#include "INetwork.hpp"
//#include "IPhysicsMgr.hpp"
#include "IRenderer.hpp"

#include "Exception.hpp"
#include "String.hpp"

// Interface to handling tick events raised by Engine
class ITickHandler
{
public:
	virtual ~ITickHandler() {}
	virtual void onTick() = 0;
};

class EngineException : public ExceptionBase {
public: EngineException(String msg) : ExceptionBase(msg) {}
};

class Engine : public IInputHandler,
			   //public INetworkHandler, public IPhysicsHandler,
			   public IRendererHandler
{
	TimeKeeper<Engine>* m_timekeeper;
	
	IInput*      m_input;
	//INetwork*    m_network;
	//IWorld*      m_world;
	IRenderer*   m_renderer;
	
	ITickHandler*     m_tick_handler;
	IInputHandler*    m_input_handler;
	//INetworkHandler*  m_network_handler;
	//IPhysicsHandler*  m_physics_handler;
	IRendererHandler* m_renderer_handler;

public:
	Engine() : m_timekeeper(0), m_input(0),
			   //m_network(0), m_physics(0),
			   m_renderer(0),
			   m_tick_handler(0), m_input_handler(0),
			   //m_network_handler(0), m_physics_handler(0),
			   m_renderer_handler(0)
	{
		
	}
	virtual ~Engine()
	{
		if( m_timekeeper ) {
			delete m_timekeeper;
		}
	}
	
	void start();
	void stop() { m_timekeeper->stop(); }
	
	void setClock(IClock* clock);
	void setInput(IInput* obj)           { m_input = obj; }
	//void setNetwork(INetwork* obj)       { m_network = obj; }
	//void setWorld(IWorld* obj)           { m_world = obj; }
	void setRenderer(IRenderer* obj)     { m_renderer = obj; }

	TimeKeeper<Engine>* getTimeKeeper()
	{ return m_timekeeper; }
	IInput*      getInput()      { return m_input; }
	//INetwork*  getNetwork()      { return m_network; }
	//IWorld*    getWorld()        { return m_world; }
	IRenderer*   getRenderer()   { return m_renderer; }
	
	void setTickHandler(ITickHandler* h)         { m_tick_handler = h; }
	void setInputHandler(IInputHandler* h)       { m_input_handler = h; }
	//void setNetworkHandler(INeworkHandler* h)    { m_network_handler = h; }
	//void setPhysicsHandler(IPhysicsHandler* h)   { m_physics_handler = h; }
	void setRendererHandler(IRendererHandler* h) { m_renderer_handler = h; }
	
	void setTickRate(const Scalar& rate)
	{ m_timekeeper->setDesiredTickRate(rate); }

	// Event callbacks called as Handler for TimeKeeper
	void onMoment(TimeKeeper<Engine>* caller);
	void onTick(TimeKeeper<Engine>* caller);
	
	// Event callbacks called as IInputHandler
	virtual void onKeyDown(IInput* caller, Key key);
	virtual void onKeyUp(IInput* caller, Key key);
	virtual void onMouseDown(IInput* caller, Vector pos, Button button);
	virtual void onMouseUp(IInput* caller, Vector pos, Button button);
	virtual void onMouseMove(IInput* caller, Vector pos, Button button);
	virtual void onQuit(IInput* caller);
    // Event callbacks called as IRendererHandler
	virtual void onFrame(IRenderer* caller);
};

#endif //_ENGINE_HPP
